package luccy.desc.impl;

import java.io.Externalizable;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import luccy.desc.ClassDesc;
import luccy.util.AssertionUtil;

public class ClassDescImpl<T> implements ClassDesc<T> {

	private String componentName;

	private Class<T> targetClass;

	private List<Class> dependencyClassesList = new ArrayList<Class>();

	private Map<String, Class[]> classesMap = new HashMap<String, Class[]>();

	private static Set<Class> unacceptableClasses = new HashSet<Class>();

	static {
		unacceptableClasses.add(Cloneable.class);
		unacceptableClasses.add(Comparable.class);
		unacceptableClasses.add(Serializable.class);
		unacceptableClasses.add(Externalizable.class);
	}

	public ClassDescImpl(Class<T> targetClass) {
		this(null, targetClass);
	}

	public ClassDescImpl(String componentName, Class<T> targetClass) {
		this.targetClass = targetClass;
		analyzeClassDependency(targetClass);
		if (componentName != null) {
			this.componentName = componentName;
			setUpComponentNameMap(componentName, dependencyClassesList);
		}
	}

	protected void setUpComponentNameMap(final String componentName,
			List<Class> classesList) {
		final Class[] array = classesList
				.toArray(new Class[classesList.size()]);
		classesMap.put(componentName, array);
	}

	protected void analyzeClassDependency(Class targetClass) {
		for (Class c = targetClass; c != null && c != Object.class; c = c.getSuperclass()) {
			analyzeByInterface(c);
		}
	}

	protected void analyzeByInterface(final Class c) {
		if (isUnacceptableClass(c)) {
			return;
		}
		addDependencyClass(c);
		final Class[] interfaces = c.getInterfaces();
		for (Class cl : interfaces) {
			analyzeByInterface(cl);
		}
	}

	protected void addDependencyClass(final Class clazz) {
		dependencyClassesList.add(clazz);
	}

	public Map<String, Class[]> getClassesMap() {
		return classesMap;
	}

	public Class<T> getComponentClass() {
		return targetClass;
	}

	public List<Class> getDependencyClassesList() {
		return dependencyClassesList;
	}

	public boolean isUnacceptableClass(Class c) {
		return unacceptableClasses.contains(c);
	}

	public static void addUnacceptableClass(Class c) {
		AssertionUtil.assertNotNull(c);
		unacceptableClasses.add(c);
	}

	public String getComponentName() {
		return componentName;
	}

}
